-
-
Notifications
You must be signed in to change notification settings - Fork 826
✨ Support for pydantic options #803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
📝 Docs preview for commit 12be77e at: https://ab20f60a.typertiangolo.pages.dev |
ProblemIf we want to allow sequences of pydantic models, things get unreadable quite fast. Let's look at an example of a nested pydantic model with a sequence of another model: from typing import Optional, List
import typer
import pydantic
class Pet(pydantic.BaseModel):
name: str
species: str
class Person(pydantic.BaseModel):
name: str
age: Optional[float] = None
pets: List[Pet]
def main(person: Person):
print(person, type(person))
if __name__ == "__main__":
typer.run(main)The script could be called like this: $ python pets.py --person.name Jeff --person.pets.name Lassie --person.pets.species dogIf we want to add multiple pets, we can just supply $ python pets.py --person.name Jeff --person.pets.name Lassie --person.pets.species dog --person.pets.name Nala --person.pets.species catWe don't explicitly state which pet names and species belong together and have to rely on the correct order of parameters. In my opinion this is potentially confusing for the CLI user and may lead to bugs. Potential SolutionTo make the mapping more explicit, we could allow to enable Indexed lists could be implemented independently of this PR and should work for all lists.
from typing import List
import typer
def main(indexed_list: List[int] = typer.Option(..., indexed=True)):
print(indexed_list)
if __name__ == "__main__":
typer.run(main)This would then produce the following help text: $ python indexed_list.py --help
Usage: indexed_list.py [OPTIONS]
╭─ Options ────────────────────────────────────────────────────────╮
│ * --indexed-list[n] INTEGER [default: None] [required] │
│ --help Show this message and │
│ exit. │
╰──────────────────────────────────────────────────────────────────╯And could be used like this: $ python indexed_list.py --indexed-list[1] 0 --indexed-list[0] 1 --indexed-list[2] 2
[1, 0, 2]Note how the order of the input parameters doesn't matter anymore because the indices are given explicitly. Notes on ImplementationImplementing this might not be trivial, but I think it could be possible by forwarding unknown options as described in the Edit: This might actually be easier using token normalization. Do you have any opinions on this? |
|
@pypae why limiting the pydantic models to My current use case requires a set of commands with a
I'm not sure how many users would required deep nested commands in their CLI, and if that's the case using a |
|
I started working on a standalone package to support this functionality, so you can use It's still WIP, and for now only covers the same basic behavior as this PR. |
|
This pull request has a merge conflict that needs to be resolved. |
svlandeg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't reviewed this in detail yet, but just quickly a few administrative points that we'd need to address if we do want to go forward with this PR:
- The tutorial files should be updated to use
Typer()instead oftyper.run, the new format since #1418 - There should be a new markdown file
docs/tutorial/parameter-types/pydantic.mdexplaining this and referencing the tutorial files. This file should be included inmkdocs.yml.
📝 Summary
This PR adds support for pydantic options as requested in the following issue: #111
In particular it implements the behavior I described in #111 (comment).
The implementation changes the signature of the callback to add all fields of the (possibly nested)
pydanticmodels of the original callback astyper.Options. As a result the implementation is largely independent oftyperand could also be used as a standalone package which could be activated with an additional decorator on the command functions:Usage as a decorator (draft)
🔀 Related PRs
☑️ To Do
typer.Optionandtyper.ArgumentinsidepydanticmodelspydanticmodelsAllow sequences of pydantic models.I suggest implementing indexed list options first, see the comment below.